import getClientSize from './getClientSize.js'

const ellArr = [
    { class: '.ell-l', type: 'left' },
    { class: '.ell-r', type: 'right' },
    { class: '.ell-t', type: 'top' },
    { class: '.ell-b', type: 'bottom' },
]
const ellAlwaysArr = [
    { class: '.ell-a-l', type: 'left' },
    { class: '.ell-a-r', type: 'right' },
    { class: '.ell-a-t', type: 'top' },
    { class: '.ell-a-b', type: 'bottom' },
]
const ellMultipleArr = [
    { class: '.ell-m-l', type: 'left' },
    { class: '.ell-m-r', type: 'right' },
    { class: '.ell-m-t', type: 'top' },
    { class: '.ell-m-b', type: 'bottom' },
    // 用于兼容上个版本的命名
    { class: '.elln-l', type: 'left' },
    { class: '.elln-r', type: 'right' },
    { class: '.elln-t', type: 'top' },
    { class: '.elln-b', type: 'bottom' },
]
function setEllItem(dom, type) {
    const padding = 5 //定义弹框距边界的位置
    const anglePadding = 9 //定义小三角距边界的位置，padding加上圆角尺寸
    // 获取dom的尺寸
    const { innerText, clientWidth, clientHeight } = dom
    const { w, h } = getClientSize() //浏览器可见区域高宽尺寸
    const { left, top, bottom, right } = dom.getClientRects()[0]
    let content = dom.getAttribute('ell-value')
    if (!content) {
        if (innerText) {
            content = innerText
            dom.setAttribute('ell-value', content)
        } else {
            return
        }
    }

    // 获取目标dom的style并封装成对象，便于修改
    let cssTextArr = dom.style.cssText.split(';')
    let cssObj = {}
    cssTextArr.forEach((item) => {
        let arr = item.split(':')
        cssObj[arr[0]] = arr[1]
    })

    //获取ell:after的尺寸
    let afterDom = window.getComputedStyle(dom, ':after')
    let afterWidth = parseInt(afterDom.width)
    let afterMaxWidth = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--ell-max-width'))
    if (afterWidth >= afterMaxWidth) {
        cssObj['--ell-wrap'] = 'pre-wrap'
        cssObj['--ell-min-width'] = afterMaxWidth
        cssObj['--ell-width'] = afterMaxWidth
    } else {
        cssObj['--ell-wrap'] = 'nowrap'
        cssObj['--ell-width'] = afterDom.width
    }
    let cssString = ''
    for (let key in cssObj) {
        cssString += key + ':' + cssObj[key] + ';'
    }
    dom.style.cssText = cssString
    // return
    afterDom = window.getComputedStyle(dom, ':after')
    var { paddingBottom, paddingLeft, paddingRight, paddingTop, height, width, borderWidth } = afterDom
    let obj = {
        paddingBottom,
        paddingLeft,
        paddingRight,
        paddingTop,
        height,
        width,
        borderWidth,
    }
    for (let key in obj) {
        obj[key] = parseInt(obj[key])
    }
    var { paddingBottom, paddingLeft, paddingRight, paddingTop, height, width, borderWidth } = obj

    borderWidth = borderWidth || 0 //在firefox中为空字符串，parseInt后为NaN
    const afterDomOffsetWidth = width + paddingLeft + paddingRight + borderWidth * 2

    const afterDomOffsetHeight = height + paddingTop + paddingBottom + borderWidth * 2

    //获取ell:before，即气泡框上的小三角的尺寸
    const beforeDom = window.getComputedStyle(dom, ':before')

    const beforeDomWidth = parseInt(beforeDom.width) + 2 * parseInt(beforeDom.borderWidth)

    // 根据上一步获取的尺寸，计算ell堤示框能否在视野内完全显示，若不能，强制更换其显示位置
    if (left - afterDomOffsetWidth - beforeDomWidth < 0 && type === 'left') type = 'right'
    if (right + afterDomOffsetWidth + beforeDomWidth > w && type === 'right') type = 'left'
    if (top - afterDomOffsetHeight - beforeDomWidth < 0 && type === 'top') type = 'bottom'
    if (bottom + afterDomOffsetHeight + beforeDomWidth > h && type === 'bottom') type = 'top'

    //根据ell位置，给style对象设置新值
    let ellLeft = padding
    let ellTop = padding
    let angleTop = anglePadding
    switch (type) {
        case 'top':
            ellLeft = left - (afterDomOffsetWidth - clientWidth) / 2
            ellLeft = Math.max(ellLeft, padding)
            ellLeft = Math.min(ellLeft, w - afterDomOffsetWidth - padding)
            cssObj['--ell-left'] = `${ellLeft}px`
            cssObj['--ell-top'] = `${top - afterDomOffsetHeight - (beforeDomWidth / 2) * Math.sqrt(2)}px`
            cssObj['--ell-angle-left'] = `${left + clientWidth / 2 - beforeDomWidth / 2}px`
            cssObj['--ell-angle-top'] = `${top - beforeDomWidth - (beforeDomWidth / 2) * (Math.sqrt(2) - 1)}px`
            break
        case 'bottom':
            ellLeft = left - (afterDomOffsetWidth - clientWidth) / 2
            ellLeft = Math.max(ellLeft, padding)
            ellLeft = Math.min(ellLeft, w - afterDomOffsetWidth - padding)
            cssObj['--ell-left'] = `${ellLeft}px`
            cssObj['--ell-top'] = `${bottom + (beforeDomWidth / 2) * Math.sqrt(2)}px`
            cssObj['--ell-angle-left'] = `${left + clientWidth / 2 - beforeDomWidth / 2}px`
            cssObj['--ell-angle-top'] = `${bottom + (beforeDomWidth / 2) * (Math.sqrt(2) - 1)}px`
            break
        case 'right':
            ellTop = top - (afterDomOffsetHeight - clientHeight) / 2
            ellTop = Math.max(ellTop, padding)
            ellTop = Math.min(ellTop, h - afterDomOffsetHeight - padding)

            angleTop = top + (clientHeight - beforeDomWidth) / 2
            angleTop = Math.max(angleTop, anglePadding)
            angleTop = Math.min(angleTop, h - beforeDomWidth * 2 - anglePadding)

            cssObj['--ell-left'] = `${right + (beforeDomWidth / 2) * Math.sqrt(2)}px`
            cssObj['--ell-top'] = `${ellTop}px`
            cssObj['--ell-angle-left'] = `${right + (beforeDomWidth / 2) * (Math.sqrt(2) - 1)}px`
            cssObj['--ell-angle-top'] = `${angleTop}px`

            break
        case 'left':
            ellTop = top - (afterDomOffsetHeight - clientHeight) / 2
            ellTop = Math.max(ellTop, padding)
            ellTop = Math.min(ellTop, h - afterDomOffsetHeight - padding)

            angleTop = top + (clientHeight - beforeDomWidth) / 2
            angleTop = Math.max(angleTop, anglePadding)
            angleTop = Math.min(angleTop, h - beforeDomWidth * 2 - anglePadding)

            cssObj['--ell-left'] = `${left - afterDomOffsetWidth - (beforeDomWidth / 2) * Math.sqrt(2)}px`
            cssObj['--ell-top'] = `${ellTop}px`
            cssObj['--ell-angle-left'] = `${left - beforeDomWidth - (beforeDomWidth / 2) * (Math.sqrt(2) - 1)}px`
            cssObj['--ell-angle-top'] = `${angleTop}px`
            break
        default:
            break
    }

    //将新的style对象重新拼接成字符串
    let cssTextString = ''
    for (let key in cssObj) {
        cssTextString += key + ':' + cssObj[key] + ';'
    }
    let tooltip = document.getElementById('simply-ellipsis-tooltip')
    if (!tooltip) {
        tooltip = document.createElement('div')
        tooltip.setAttribute('id', 'simply-ellipsis-tooltip')
        document.body.append(tooltip)
    }
    tooltip.setAttribute('ell-value', content)
    tooltip.style.cssText = cssTextString
    // 根据实际的ell提示框位置来设置气泡框小三角的朝向
    ellArr.forEach((item) => {
        tooltip.classList.remove('has-ell-' + item.type)
    })
    tooltip.classList.add('has-ell-' + type)
    tooltip.classList.add('has-ell')
    tooltip.classList.add('has-ell-visibility')
}

export const setEll = function () {
    ellArr.forEach((item) => {
        document.querySelectorAll(item.class).forEach((dom) => {
            if (isOverFlow(dom)) {
                setEllAction(dom, item.type)
            }
        })
    })
    ellAlwaysArr.forEach((item) => {
        document.querySelectorAll(item.class).forEach((dom) => {
            setEllAction(dom, item.type)
        })
    })
    ellMultipleArr.forEach((item) => {
        document.querySelectorAll(item.class).forEach((dom) => {
            if (dom.scrollHeight > dom.offsetHeight) {
                setEllAction(dom, item.type)
            }
        })
    })
}

function isOverFlow(dom) {
    if (dom.scrollWidth > dom.offsetWidth) {
        return true
    }

    const domStyle = document.defaultView.getComputedStyle(dom, '')
    const padding = parseInt(domStyle.paddingLeft || 0) + parseInt(domStyle.paddingRight || 0)

    const range = document.createRange()
    range.setStart(dom, 0)
    range.setEnd(dom, dom.childNodes.length)
    const rangeWidth = range.getBoundingClientRect().width

    return rangeWidth + padding > dom.offsetWidth
}

function setEllAction(dom, type) {
    // 获取浏览器信息，并转小写
    let userAgent = navigator.userAgent.toLowerCase()
    // 用 test 匹配浏览器信息
    if (/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(userAgent)) {
        dom.ontouchstart = (e) => {
            e.preventDefault()
            setEllItem(dom, type)
        }
        dom.ontouchend = (e) => {
            e.preventDefault()
            let tooltip = document.getElementById('simply-ellipsis-tooltip')
            if (tooltip) {
                tooltip.classList.remove('has-ell-visibility')
            }
        }
        dom.touchcancel = (e) => {
            e.preventDefault()
            let tooltip = document.getElementById('simply-ellipsis-tooltip')
            if (tooltip) {
                tooltip.classList.remove('has-ell-visibility')
            }
        }
    } else {
        dom.onmouseover = () => {
            setEllItem(dom, type)
        }
        dom.onmouseleave = () => {
            let tooltip = document.getElementById('simply-ellipsis-tooltip')
            if (tooltip) {
                tooltip.classList.remove('has-ell-visibility')
            }
        }
    }
}
